﻿using DotNetWebApp0514a.Models;
using Microsoft.AspNetCore.Mvc;
using Newtonsoft.Json;
using System.Collections.Generic;
using System.Diagnostics;
using System.Net;
using System.IO;
using System.Web;
using System.Collections;
using Newtonsoft.Json.Linq;
using System.Text;
using System.Net.Sockets;
using System.Text.Json;
using System.Xml.Linq;
using System;
using System.Xml.Linq;
using System.Text.Json;
using System.Data.SqlTypes;
using System.Xml.Serialization;
using System.Xml;
using System.Runtime.Serialization;
using static System.Net.Mime.MediaTypeNames;
using System.Reflection.Metadata;

// 需要搭配前端使用，有问题可以微信我号yizheng369
// 前端源码 https://gitee.com/618859/wx_gzh_scan_login_qr-code_vue.git


namespace DotNetWebApp0514a.Controllers
{


    /*
     * var data = {
            "expire_seconds": 604800,
            "action_name": "QR_SCENE",
            "action_info": {
                "scene": { "scene_id": myid }
            }
        }
     */

    
[Serializable]  
public class UserInfo  
{  
    public string Name;  
  
    public string sex;  
} 

    public class WechatData
    {
        public int expire_seconds { get; set; }
        public string action_name { get; set; }

        public ActionInfo action_info { get; set; }
    }

    public class ActionInfo
    {
        public Scene scene { get; set; }
    }

    public class Scene
    {
        public int scene_id { get; set; }
    }

    public class ResultTicket
    {
        public TicketObj data { get; set; }
    }

    public class TicketObj
    {
        public String ticket { get; set; }
    }
    public class UserData
    {
        public string id { get; set; }
        public string name { get; set; }
    }

    [Route("/")]
    public class HomeController : Controller
    {
        public ILogger<HomeController> _logger;

        public static ArrayList loginArr = new ArrayList(); // 所有扫码登录的人

        [Route("")]
        [HttpGet]
        public String index()
        {
            mylog("进入 index");
            return "hello world cs";
        }


        // 这里接收微信服务器返回的xml数据，即用户扫码后微信服务器返回的
        [Route("")]
        [HttpPost]
        public async Task<string> postIndex()
        {
            //采用排序的Dictionary的好处是方便对数据包进行签名，不用再签名之前再做一次排序
            SortedDictionary<string, object> m_values = new SortedDictionary<string, object>();
            // 原文链接：https://blog.csdn.net/mrtraum/article/details/80897239
            mylog("--- 进入 微信服务器返回 ---");
            string xml;
            using (System.IO.StreamReader reader = new System.IO.StreamReader(Request.Body, Encoding.UTF8))
            {
                xml = await reader.ReadToEndAsync();
            }
            // xml = "<?xml version=\"1.0\" encoding=\"utf-8\"?>" + xml;
            mylog("xml:" + xml);

            var str = "<?xml version=\"1.0\" encoding=\"utf-16\"?><UserInfo xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\" xmlns:xsd=\"http://www.w3.org/2001/XMLSchema\"><Name>bdstjk</Name><sex>男</sex></UserInfo>";

            // UserInfo user = XmlSerialize.DeserializeXML<UserInfo>(str);
            xml user = XmlSerialize.DeserializeXML<xml>(xml);

            // 原文链接1：https://phoenix.blog.csdn.net/article/details/104488430?spm=1001.2101.3001.6650.2&utm_medium=distribute.pc_relevant.none-task-blog-2%7Edefault%7EBlogCommendFromBaidu%7ERate-2-104488430-blog-104422943.235%5Ev36%5Epc_relevant_default_base3&depth_1-utm_source=distribute.pc_relevant.none-task-blog-2%7Edefault%7EBlogCommendFromBaidu%7ERate-2-104488430-blog-104422943.235%5Ev36%5Epc_relevant_default_base3&utm_relevant_index=3

            // 原文链接2：https://blog.csdn.net/mrtraum/article/details/80897239

            mylog("解析后："+ JsonConvert.SerializeObject(user));
            // loginArr.SetValue(23, loginArr.Length);

            // 如果是第一次扫码关注是返回 EventKey: 'qrscene_47338'
            int theIndex = user.EventKey.IndexOf("_");
            if (theIndex != -1)
            {
                user.EventKey = user.EventKey.Substring(theIndex+1);
            }
            loginArr.Add(int.Parse(user.EventKey));
            // mylog("loginArr:" + JsonConvert.SerializeObject(loginArr));

            user.printString();

            // 这里严格的话，还要根据场景，重新组装xml返回给微信服务器
            // 获得返回的xml
            String backXml = "text";
            if(user.Event != "unsubscribe")
            {
                backXml = getBackXml(user);
            } else
            {
                mylog("他不关注了");
            }
                
            return backXml;
        }

        public String getBackXml(xml user)
        {
            // 生成返回实例
            backXml bXml = new backXml();
            // 改造user
            bXml.ToUserName = user.FromUserName;
            bXml.FromUserName = user.ToUserName;
            bXml.CreateTime = (int.Parse(user.CreateTime) + 200).ToString();
            bXml.MsgType = "text";
            switch (user.Event)
            {
                case "subscribe":
                    bXml.Content = "欢迎您的关注";
                    break;
                case "SCAN":
                    bXml.Content = "好家伙，扫码关注";
                    break;
                default:
                    bXml.Content = "其他事件";
                    break;
            }
            // String xmlStr = XmlSerialize.SerializeXML<backXml>(bXml);
            String msgStr = "<xml>"
              +"\r\n<ToUserName><![CDATA["+ bXml.ToUserName + "]]></ToUserName>"
              + "\r\n<FromUserName><![CDATA[" + bXml.FromUserName + "]]></FromUserName>"
              + "\r\n<CreateTime>" + bXml.CreateTime + "</CreateTime>"
              + "\r\n<MsgType><![CDATA[text]]></MsgType>"
              + "\r\n<Content><![CDATA[" + bXml.Content + "]]></Content>"
            + "\r\n</xml>";
            mylog("组装后xmlStr: " + msgStr);
            return msgStr;
        }


        [Route("kkk")]
        [HttpGet]
        public String kkk()
        {
            mylog("进入 kkk");
            return "woshi kkk";
        }


        public void mylog(String str, String str1="")
        {
            System.Diagnostics.Debug.WriteLine(str, str1);
        }

        [Route("Login")]
        [HttpGet]
        public Boolean Login(int myid)
        {

            mylog("有人问" + myid);
            mylog("loginArr:" + JsonConvert.SerializeObject(loginArr));
            int index = loginArr.IndexOf(myid);
            mylog("index: " + index.ToString());
            if (index == -1)
            {
                return false;
            }
            else
            {
                return true;
            }

        }

        // 退出登录
        [Route("Logout")]
        [HttpGet]
        public Boolean Logout(int myid)
        {
            mylog("有人退出登录" + myid);
            mylog("loginArr:" + JsonConvert.SerializeObject(loginArr));
            int index = loginArr.IndexOf(myid);
            mylog("index: " + index.ToString());
            if(index != -1)
            {
                loginArr.RemoveRange(index, 1);
            }
            return true;
        }


        public HomeController(ILogger<HomeController> logger)
        {
            _logger = logger;
        }

        public IActionResult Index()
        {
            mylog("进入 Index");
            return View();
        }

        public IActionResult Privacy()
        {
            mylog("进入 Privacy");
            return View();
        }

        [Route("getQrCode")]
        [HttpPost]
        public async Task<string> getQrCodeAsync([FromBody]WechatData data)
        {
            // 微信公众号资料
            String appId = "wx3680aee5b396cc0f"; // 这个要改成你自己的
            String appsecret = "626c988a2e4af8cc459424187951792e"; // 这个要改成你自己的
            String token_url = "https://api.weixin.qq.com/cgi-bin/token?grant_type=client_credential&appid="+appId+"&secret="+appsecret;

            var access_token = await getNewTokenAsync(token_url);
            mylog("task-access_token:" + access_token);

            String jsonStr = JsonConvert.SerializeObject(data);
            System.Diagnostics.Debug.WriteLine("收到wx：" + jsonStr);
            var ticket = await getTicketAsync(access_token, jsonStr);

            mylog("task-ticket:" + ticket);

            
            TicketObj tObj = new TicketObj();
            tObj.ticket = ticket;
            String ticketJson = JsonConvert.SerializeObject(tObj);
            return ticketJson;
        }

        private static readonly HttpClient client = new HttpClient();
        public async Task<string> getNewTokenAsync(String token_url)
        {

            //发送Get请求
            var responseString = await client.GetStringAsync(token_url);
            mylog("getNewTokenAsync结果：" + responseString);
            // var DeJsonStr = JsonConvert.DeserializeObject(responseString);
            var jObject = JObject.Parse(responseString);
            var access_token = jObject["access_token"].ToString();
            mylog("access_token:" + access_token);
            return access_token;
        }

        // 获取ticket
        public async Task<string> getTicketAsync(String access_token, String json)
        {
            
            String url = "https://api.weixin.qq.com/cgi-bin/qrcode/create?access_token="+ access_token;

            //发送Post请求 https://www.codenong.com/23585919/
            // var content = new FormUrlEncodedContent(str);
            var httpContent = new StringContent(json, Encoding.UTF8, "application/json");
            var response = await client.PostAsync(url, httpContent);
            var responseString = await response.Content.ReadAsStringAsync();
            mylog("getNewTokenAsync结果2：" + responseString);

            var jObject = JObject.Parse(responseString);
            var ticket = jObject["ticket"].ToString();
            mylog("ticket:" + ticket);
            return ticket;
        }

        public String PostFun()
        {
            // 参考文章 https://blog.csdn.net/a991361563/article/details/108209302
            //发送Post请求
            /*var values = new Dictionary
            {
               { "thing1", "hello" },
               { "thing2", "world" }
            };
            var content = new FormUrlEncodedContent(values);
            var response = await client.PostAsync("http://www.example.com/recepticle.aspx", content);
            var responseString = await response.Content.ReadAsStringAsync()*/
            return "Sd";
        }

        // 能自动装配form表单数据 theJson(StuData stu)
        // 但不能自动装配json，要这样 theJson([FromBody]UserData stu)
        public List<UserData> theJson([FromBody]UserData stu)
        {
            String str = JsonConvert.SerializeObject(stu);
            System.Diagnostics.Debug.WriteLine("收到："+str);


            // Request.QueryString["ssss"].ToString();

            List<UserData> dataList = new List<UserData>() {
                new UserData {id="1",name="asd" },
            };
            String theJson = JsonConvert.SerializeObject(dataList);
            System.Diagnostics.Debug.WriteLine("theJson:" + theJson);

            return dataList;

            // 原文链接：https://blog.csdn.net/wesleysd/article/details/123065099
        }

        [ResponseCache(Duration = 0, Location = ResponseCacheLocation.None, NoStore = true)]
        public IActionResult Error()
        {
            System.Diagnostics.Debug.Write("进入 Error");
            return View(new ErrorViewModel { RequestId = Activity.Current?.Id ?? HttpContext.TraceIdentifier });
        }
    }

    /*
     * <xml>
     *  <ToUserName><![CDATA[gh_b3958963bb18]]></ToUserName>
        <FromUserName><![CDATA[od4SM6Y8InFQGhkteIAE]]></FromUserName>
        <CreateTime>1684422327</CreateTime>
        <MsgType><![CDATA[event]]></MsgType>
        <Event><![CDATA[SCAN]]></Event>
        <EventKey><![CDATA[32899]]></EventKey>
        <Ticket><![CDATA[gQGY8DwAAAAAAAwSAOgkA]]></Ticket>
       </xml>
     */
    public class xml
    {
        public string ToUserName { get; set; }
        public string FromUserName { get; set; }
        public string CreateTime { get; set; }
        public string MsgType { get; set; }
        public string Event { get; set; }
        public string EventKey { get; set; }
        public string Ticket { get; set; }

        public void printString()
        {
            System.Diagnostics.Debug.WriteLine(
                "ToUserName:" + this.ToUserName +
                "\r\nFromUserName:" + this.FromUserName +
                "\r\nCreateTime:" + this.CreateTime +
                "\r\nMsgType:" + this.MsgType +
                "\r\nEvent:" + this.Event +
                "\r\nEventKey:" + this.EventKey +
                "\r\nTicket:" + this.Ticket
            );
        }
    }
    public class backXml
    {
        public string ToUserName { get; set; }
        public string FromUserName { get; set; }
        public string CreateTime { get; set; }
        public string MsgType { get; set; }
        public string Content { get; set; }
    }
}